package com.google.code.synchunit;

public abstract class MonitoredThread extends Thread {

	boolean executionCompleted;
	boolean skipBreakPoints;
	private BlockDetector blokDetector;

	public MonitoredThread(String name) {
		super(name);
		synchronized (this) {
			start();
			try {
				wait();
			} catch (InterruptedException ie) {
				throw new IllegalStateException(
						"Execution interrupted. Cannot Initialize MonitoredThread.");
			}
		}
	}

	public MonitoredThread() {
		this(null);
	}

	public void run() {
		synchronized (this) {
			try {
				// starting but waiting to resume
				notify();
				wait();
			} catch (InterruptedException ie) {
				throw new IllegalStateException(
						"Execution interrupted. Nobody notified Thread " + this
								+ " to resume.");
			}
		}

		executeCode();
		executionCompleted = true;

		synchronized (this) {
			// notify termination
			notify();
		}
	}

	public abstract void executeCode();

	public synchronized void resumeExecution() {
		blokDetector = new BlockDetector(this);
		blokDetector.start();
		try {
			notify();
			wait();

		} catch (InterruptedException ie) {
			throw new IllegalStateException(
					"Execution interrupted. Nobody notified Thread " + this
							+ " to resume.");
		}
	}

	public synchronized void suspendExecution() {
		if (skipBreakPoints) {
			return;
		}

		blokDetector.terminate();
		try {
			notify();
			wait();
		} catch (InterruptedException ie) {
			throw new IllegalStateException(
					"Execution interrupted. Nobody notified Thread " + this
							+ " to resume.");
		}
	}

	@Override
	public State getState() {
		if (executionCompleted) {
			return State.TERMINATED;
		}
		return super.getState();
	}

	public void skipAllBreakpoints() {
		this.skipBreakPoints = true;
	}

	public void restoreAllBreakpoints() {
		this.skipBreakPoints = false;
	}
}
